package com.compomics.proteocloud.ui;

import javax.swing.*;

import com.compomics.proteocloud.db.accessor.Pepnovohit;
import com.compomics.proteocloud.io.MascotGenericFile;
import com.compomics.proteocloud.model.DenovoHitSet;
import com.compomics.proteocloud.model.DenovoSearchResult;
import com.compomics.proteocloud.sqs.MessageManager;
import com.compomics.proteocloud.starter.CloudTools;
import com.compomics.proteocloud.util.*;
import com.compomics.util.experiment.biology.Ion;
import com.compomics.util.experiment.biology.IonFactory;
import com.compomics.util.experiment.biology.NeutralLoss;
import com.compomics.util.experiment.biology.Peptide;
import com.compomics.util.experiment.biology.ions.PeptideFragmentIon;
import com.compomics.util.experiment.identification.SpectrumAnnotator;
import com.compomics.util.experiment.identification.matches.IonMatch;
import com.compomics.util.experiment.identification.matches.ModificationMatch;
import com.compomics.util.experiment.identification.matches.PeptideMatch;
import com.compomics.util.experiment.massspectrometry.Charge;
import com.compomics.util.experiment.massspectrometry.MSnSpectrum;
import com.compomics.util.experiment.massspectrometry.Peak;
import com.compomics.util.experiment.massspectrometry.Precursor;
import com.compomics.util.gui.protein.ModificationProfile;
import com.compomics.util.gui.protein.SequenceModificationPanel;
import com.compomics.util.gui.spectrum.SpectrumPanel;
import com.compomics.util.preferences.AnnotationPreferences;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

import com.xerox.amazonws.sqs2.SQSException;
import no.uib.jsparklines.renderers.JSparklinesBarChartTableCellRenderer;
import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.JXTitledPanel;
import org.jdesktop.swingx.decorator.HighlighterFactory;
import org.jfree.chart.plot.PlotOrientation;


import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.sql.SQLException;
import java.util.*;
import java.util.List;

public class DenovoResultPanel extends JPanel {

    private JXTable spectraTbl;
    private JXTable denovoTbl;
    private Map<String, DenovoHitSet> titleToSetMap;
    private SpectrumPanel spectrumPanel;
    private JPanel spectrumJPanel;
    private CellConstraints cc;
    private ProteoCloudUI mainFrame;
    private Peptide peptide;
    private List<String> denovoTableToolTips;
    private List<String> spectraTableToolTips;
    private JMenuBar annotationMenuBar;
    private JMenu ionsMenu;
    private JCheckBoxMenuItem aIonCheckBoxMenuItem;
    private JCheckBoxMenuItem bIonCheckBoxMenuItem;
    private JCheckBoxMenuItem cIonCheckBoxMenuItem;
    private JCheckBoxMenuItem xIonCheckBoxMenuItem;
    private JCheckBoxMenuItem yIonCheckBoxMenuItem;
    private JCheckBoxMenuItem zIonCheckBoxMenuItem;
    private JMenu splitterMenu1;
    private JMenu splitterMenu2;
    private JMenu splitterMenu3;
    private JMenu splitterMenu4;
    private JMenu splitterMenu5;
    private JMenu splitterMenu6;
    private JMenu splitterMenu7;
    private JMenu otherMenu;
    private JMenu lossMenu;
    private JMenu settingsMenu;
    private JMenu chargeMenu;
    private JMenu deNovoMenu;
    private JCheckBoxMenuItem reporterIonsCheckMenuItem;
    private JCheckBoxMenuItem precursorCheckMenuItem;
    private JCheckBoxMenuItem immoniumIonsCheckMenuItem;
    private JCheckBoxMenuItem forwardIonsDeNovoCheckBoxMenuItem;
    private JCheckBoxMenuItem rewindIonsDeNovoCheckBoxMenuItem;
    private JCheckBoxMenuItem allCheckBoxMenuItem;
    private JCheckBoxMenuItem barsCheckBoxMenuItem;
    private ButtonGroup deNovoChargeButtonGroup;
    private JCheckBoxMenuItem deNovoChargeOneJRadioButtonMenuItem;
    private JCheckBoxMenuItem deNovoChargeTwoJRadioButtonMenuItem;
    /**
     * The annotation preferences.
     */
    private AnnotationPreferences annotationPreferences = new AnnotationPreferences();

    /**
     * The charge menus.
     */
    private HashMap<Integer, JCheckBoxMenuItem> chargeMenus = new HashMap<Integer, JCheckBoxMenuItem>();

    /**
     * The neutral loss menus.
     */
    private HashMap<NeutralLoss, JCheckBoxMenuItem> lossMenus = new HashMap<NeutralLoss, JCheckBoxMenuItem>();

    /**
     * The selected spectrum.
     */
    private MascotGenericFile selectedSpectrum;

    /**
     * Constructs the DenovoResultPanel.
     *
     * @param mainFrame
     */
    public DenovoResultPanel(ProteoCloudUI mainFrame) {
        this.mainFrame = mainFrame;
        initComponents();
        // Add neutral losses.
        IonFactory.getInstance().addDefaultNeutralLoss(NeutralLoss.NH3);
        IonFactory.getInstance().addDefaultNeutralLoss(NeutralLoss.H2O);
    }

    /**
     * Initialize the components.
     */
    private void initComponents() {

        cc = new CellConstraints();

        // Setup the annotation menu bar.
        setupAnnotationMenuBar();

        // Build the spectrum overview panel
        JPanel spectrumOverviewPnl = new JPanel(new BorderLayout());
        spectrumJPanel = new JPanel();
        spectrumJPanel.setLayout(new BorderLayout());
        spectrumJPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
        spectrumJPanel.add(new SpectrumPanel(new double[]{0.0, 100.0}, new double[]{100.0, 0.0}, 0.0, "", ""));
        spectrumJPanel.setPreferredSize(new Dimension(100, 320));
        spectrumOverviewPnl.add(spectrumJPanel);
        spectrumOverviewPnl.add(annotationMenuBar, BorderLayout.SOUTH);

        spectrumOverviewPnl.setBorder(BorderFactory.createTitledBorder("Spectrum Viewer"));

        // Setup the tables
        setupSpectraTableProperties();
        setupDenovoTableProperties();

        JScrollPane querySpectraTblPane = new JScrollPane(spectraTbl);
        querySpectraTblPane.setPreferredSize(new Dimension(430, 200));

        this.setLayout(new FormLayout("5dlu, p:g, 5dlu, p:g, 5dlu", "5dlu, f:p:g, 5dlu, f:p:g, 5dlu"));

        // Choose your spectra
        JPanel resultsSpectrumPnl = new JPanel();
        resultsSpectrumPnl.setBorder(BorderFactory.createTitledBorder("Query Spectra"));
        resultsSpectrumPnl.setLayout(new FormLayout("5dlu, p:g, 5dlu", "5dlu, t:p:g, 5dlu,"));
        resultsSpectrumPnl.add(querySpectraTblPane, cc.xy(2, 2));

        // De novo results
        JPanel resultHitsPnl = new JPanel();
        resultHitsPnl.setLayout(new FormLayout("5dlu, p:g, 5dlu", "5dlu, t:p:g, 5dlu"));

        JScrollPane denovoHitsPane = new JScrollPane(denovoTbl);
        denovoHitsPane.setPreferredSize(new Dimension(570, 200));
        denovoHitsPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        denovoHitsPane.setToolTipText("Select spectra");
        resultHitsPnl.add(denovoHitsPane, cc.xy(2, 2));
        resultHitsPnl.setBorder(BorderFactory.createTitledBorder("De Novo Hits"));

        // Update the annotations preferences once
        annotationPreferences.useAutomaticAnnotation(true);
        updateAnnotationPreferences();

        this.add(spectrumOverviewPnl, cc.xyw(2, 2, 3));
        this.add(resultsSpectrumPnl, cc.xy(2, 4));
        this.add(resultHitsPnl, cc.xy(4, 4));
    }

    /**
     * This methods setups the annotation menu bar.
     */
    private void setupAnnotationMenuBar() {
        annotationMenuBar = new JMenuBar();
        splitterMenu1 = new JMenu();
        splitterMenu2 = new JMenu();
        splitterMenu3 = new JMenu();
        splitterMenu4 = new JMenu();
        splitterMenu5 = new JMenu();
        splitterMenu6 = new JMenu();
        splitterMenu7 = new JMenu();
        ionsMenu = new JMenu();
        aIonCheckBoxMenuItem = new JCheckBoxMenuItem();
        bIonCheckBoxMenuItem = new JCheckBoxMenuItem();
        cIonCheckBoxMenuItem = new JCheckBoxMenuItem();
        xIonCheckBoxMenuItem = new JCheckBoxMenuItem();
        yIonCheckBoxMenuItem = new JCheckBoxMenuItem();
        zIonCheckBoxMenuItem = new JCheckBoxMenuItem();
        precursorCheckMenuItem = new JCheckBoxMenuItem();
        reporterIonsCheckMenuItem = new JCheckBoxMenuItem();
        immoniumIonsCheckMenuItem = new JCheckBoxMenuItem();
        forwardIonsDeNovoCheckBoxMenuItem = new JCheckBoxMenuItem();
        rewindIonsDeNovoCheckBoxMenuItem = new JCheckBoxMenuItem();
        deNovoChargeOneJRadioButtonMenuItem = new JCheckBoxMenuItem();
        deNovoChargeTwoJRadioButtonMenuItem = new JCheckBoxMenuItem();
        allCheckBoxMenuItem = new JCheckBoxMenuItem();
        barsCheckBoxMenuItem = new JCheckBoxMenuItem();
        otherMenu = new JMenu();
        lossMenu = new JMenu();
        chargeMenu = new JMenu();
        deNovoMenu = new JMenu();
        settingsMenu = new JMenu();
        deNovoChargeButtonGroup = new ButtonGroup();
        annotationMenuBar.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        annotationMenuBar.setOpaque(false);
        splitterMenu1.setText("|");
        splitterMenu1.setEnabled(false);
        annotationMenuBar.add(splitterMenu1);
        ionsMenu.setText("Ions");
        ionsMenu.setEnabled(false);
        aIonCheckBoxMenuItem.setText("a");
        aIonCheckBoxMenuItem.setToolTipText("a-ions");
        aIonCheckBoxMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateAnnotationPreferences();
            }
        });
        ionsMenu.add(aIonCheckBoxMenuItem);
        bIonCheckBoxMenuItem.setText("b");
        bIonCheckBoxMenuItem.setSelected(true);
        bIonCheckBoxMenuItem.setToolTipText("b-ions");
        bIonCheckBoxMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateAnnotationPreferences();
            }
        });
        ionsMenu.add(bIonCheckBoxMenuItem);

        cIonCheckBoxMenuItem.setText("c");
        cIonCheckBoxMenuItem.setToolTipText("c-ions");
        cIonCheckBoxMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateAnnotationPreferences();
            }
        });
        ionsMenu.add(cIonCheckBoxMenuItem);

        xIonCheckBoxMenuItem.setText("x");
        xIonCheckBoxMenuItem.setToolTipText("x-ions");
        xIonCheckBoxMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateAnnotationPreferences();
            }
        });
        ionsMenu.add(xIonCheckBoxMenuItem);

        yIonCheckBoxMenuItem.setText("y");
        yIonCheckBoxMenuItem.setSelected(true);
        yIonCheckBoxMenuItem.setToolTipText("y-ions");
        yIonCheckBoxMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateAnnotationPreferences();
            }
        });
        ionsMenu.add(yIonCheckBoxMenuItem);

        zIonCheckBoxMenuItem.setText("z");
        zIonCheckBoxMenuItem.setToolTipText("z-ions");
        zIonCheckBoxMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateAnnotationPreferences();
            }
        });
        ionsMenu.add(zIonCheckBoxMenuItem);
        annotationMenuBar.add(ionsMenu);

        splitterMenu2.setText("|");
        splitterMenu2.setEnabled(false);
        annotationMenuBar.add(splitterMenu2);

        otherMenu.setText("Other");
        otherMenu.setEnabled(true);

        precursorCheckMenuItem.setSelected(true);
        precursorCheckMenuItem.setText("Precursor");
        precursorCheckMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateAnnotationPreferences();
            }
        });
        otherMenu.add(precursorCheckMenuItem);

        immoniumIonsCheckMenuItem.setSelected(true);
        immoniumIonsCheckMenuItem.setText("Immonium");
        immoniumIonsCheckMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateAnnotationPreferences();
            }
        });
        otherMenu.add(immoniumIonsCheckMenuItem);

        annotationMenuBar.add(otherMenu);

        splitterMenu3.setText("|");
        splitterMenu3.setEnabled(false);
        annotationMenuBar.add(splitterMenu3);

        lossMenu.setText("Loss");
        lossMenu.setEnabled(true);
        lossMenu.add(new JSeparator());

        annotationMenuBar.add(lossMenu);

        splitterMenu4.setText("|");
        splitterMenu4.setEnabled(false);
        annotationMenuBar.add(splitterMenu4);

        chargeMenu.setText("Charge");
        chargeMenu.setEnabled(true);
        annotationMenuBar.add(chargeMenu);

        splitterMenu5.setText("|");
        splitterMenu5.setEnabled(false);
        annotationMenuBar.add(splitterMenu5);

        deNovoMenu.setText("De Novo");

        forwardIonsDeNovoCheckBoxMenuItem.setText("f-ions");
        forwardIonsDeNovoCheckBoxMenuItem.setSelected(true);
        forwardIonsDeNovoCheckBoxMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateAnnotationPreferences();
            }
        });
        deNovoMenu.add(forwardIonsDeNovoCheckBoxMenuItem);

        rewindIonsDeNovoCheckBoxMenuItem.setText("r-ions");
        rewindIonsDeNovoCheckBoxMenuItem.setSelected(true);
        rewindIonsDeNovoCheckBoxMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateAnnotationPreferences();
            }
        });
        deNovoMenu.add(rewindIonsDeNovoCheckBoxMenuItem);
        deNovoMenu.add(new JSeparator());

        deNovoChargeButtonGroup.add(deNovoChargeOneJRadioButtonMenuItem);
        deNovoChargeOneJRadioButtonMenuItem.setSelected(true);
        deNovoChargeOneJRadioButtonMenuItem.setText("Single Charge");
        deNovoChargeOneJRadioButtonMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateAnnotationPreferences();
            }
        });
        deNovoMenu.add(deNovoChargeOneJRadioButtonMenuItem);

        deNovoChargeButtonGroup.add(deNovoChargeTwoJRadioButtonMenuItem);
        deNovoChargeTwoJRadioButtonMenuItem.setText("Double Charge");
        deNovoChargeTwoJRadioButtonMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateAnnotationPreferences();
            }
        });
        deNovoMenu.add(deNovoChargeTwoJRadioButtonMenuItem);

        annotationMenuBar.add(deNovoMenu);

        splitterMenu6.setText("|");
        splitterMenu6.setEnabled(false);
        annotationMenuBar.add(splitterMenu6);

        settingsMenu.setText("Settings");
        settingsMenu.setEnabled(true);

        allCheckBoxMenuItem.setText("Show All Peaks");
        allCheckBoxMenuItem.setToolTipText("Show all peaks or just the annotated peaks");
        allCheckBoxMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                updateAnnotationPreferences();
            }
        });
        settingsMenu.add(allCheckBoxMenuItem);

        annotationMenuBar.add(settingsMenu);

        splitterMenu7.setText("|");
        splitterMenu7.setEnabled(false);
        annotationMenuBar.add(splitterMenu7);
        annotationMenuBar.setBorder(null);
    }

    /**
     * Enables the annotation menu bar.
     */
    private void enableAnnotationMenuBar() {
        ionsMenu.setEnabled(true);
    }

    /**
     * This method prepares the denovo hits table.
     */
    private void setupDenovoTableProperties() {
        final DefaultTableModel denovoTblMdl = new DefaultTableModel() {
            // instance initializer block
            {
                setColumnIdentifiers(new Object[]{"#", "Peptide", "RankScore", "Score", "N-Gap", "C-Gap", "m/z", "Charge"});
            }

            public boolean isCellEditable(int row, int col) {
                return false;
            }

            public Class<?> getColumnClass(int columnIndex) {
                switch (columnIndex) {
                    case 0:
                    case 7:
                        return Integer.class;
                    case 2:
                    case 3:
                    case 4:
                    case 5:
                    case 6:
                        return Double.class;
                    default:
                        return String.class;
                }
            }

        };

        denovoTableToolTips = new ArrayList<String>();
        denovoTableToolTips.add("Peptide Index");
        denovoTableToolTips.add("Peptide Sequence");
        denovoTableToolTips.add("Ranking Score");
        denovoTableToolTips.add("PepNovo Score of Peptide Sequence");
        denovoTableToolTips.add("Mass Gap from N-terminal to Sequence Start");
        denovoTableToolTips.add("Mass Gap from C-terminal to Sequence End");
        denovoTableToolTips.add("Peptide m/z");
        denovoTableToolTips.add("Peptide Charge");

        denovoTbl = new JXTable(denovoTblMdl) {
            protected JTableHeader createDefaultTableHeader() {
                return new JTableHeader(columnModel) {
                    public String getToolTipText(MouseEvent e) {
                        java.awt.Point p = e.getPoint();
                        int index = columnModel.getColumnIndexAtX(p.x);
                        int realIndex = columnModel.getColumn(index).getModelIndex();
                        String tip = (String) denovoTableToolTips.get(realIndex);
                        return tip;
                    }
                };
            }
        };

        // JSparklines for Scoring
        denovoTbl.getColumn("Score").setCellRenderer(new JSparklinesBarChartTableCellRenderer(PlotOrientation.HORIZONTAL, 100.0, new Color(110, 196, 97)));
        ((JSparklinesBarChartTableCellRenderer) denovoTbl.getColumn("Score").getCellRenderer()).showNumberAndChart(true, 50, new Font("Arial", Font.PLAIN, 12), 0);

        TableColumnModel tcm = denovoTbl.getColumnModel();
        tcm.getColumn(0).setCellRenderer(new CustomTableCellRenderer(SwingConstants.RIGHT));
        tcm.getColumn(0).setMinWidth(40);
        tcm.getColumn(0).setMaxWidth(40);
        tcm.getColumn(1).setMinWidth(170);
        tcm.getColumn(1).setMaxWidth(170);
        tcm.getColumn(3).setMinWidth(100);
        tcm.getColumn(3).setMaxWidth(100);

        // Sort the peptide table by the number of peptide hits
        denovoTbl.setAutoCreateRowSorter(true);

        // register list selection listener
        denovoTbl.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                refreshSpectrumPanel();
            }
        });

        // Single selection only
        denovoTbl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        denovoTbl.setSelectionBackground(new Color(130, 207, 250));

        // Add nice striping effect
        denovoTbl.addHighlighter(HighlighterFactory.createAlternateStriping());

        // Column control
        denovoTbl.setColumnControlVisible(true);
    }

    /**
     * This method sets the spectra table up.
     */
    private void setupSpectraTableProperties() {
        // Query table
        final TableModel spectraTableMdl = new DefaultTableModel() {
            // instance initializer block
            {
                setColumnIdentifiers(new Object[]{"#", "Spectrum Title"});
            }

            public boolean isCellEditable(int row, int col) {
                return false;
            }

            public Class<?> getColumnClass(int columnIndex) {
                switch (columnIndex) {
                    case 0:
                        return Integer.class;
                    default:
                        return String.class;
                }
            }
        };

        spectraTableToolTips = new ArrayList<String>();
        spectraTableToolTips.add("Spectrum Index");
        spectraTableToolTips.add("Spectrum Title");

        spectraTbl = new JXTable(spectraTableMdl) {
            protected JTableHeader createDefaultTableHeader() {
                return new JTableHeader(columnModel) {
                    public String getToolTipText(MouseEvent e) {
                        java.awt.Point p = e.getPoint();
                        int index = columnModel.getColumnIndexAtX(p.x);
                        int realIndex = columnModel.getColumn(index).getModelIndex();
                        String tip = (String) spectraTableToolTips.get(realIndex);
                        return tip;
                    }
                };
            }
        };

        TableColumnModel tcm = spectraTbl.getColumnModel();
        tcm.getColumn(0).setCellRenderer(new CustomTableCellRenderer(SwingConstants.RIGHT));
        tcm.getColumn(0).setMinWidth(40);
        tcm.getColumn(0).setMaxWidth(40);

        // Sort the peptide table by the number of peptide hits
        spectraTbl.setAutoCreateRowSorter(true);

        // register list selection listener
        spectraTbl.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                refreshSpectrumPanel();
                refreshDenovoTable();
            }
        });

        // Single selection only
        spectraTbl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        // Add striping effect
        spectraTbl.addHighlighter(HighlighterFactory.createAlternateStriping());

        // Column control
        spectraTbl.setColumnControlVisible(true);
    }
    
    /**
     * Updates the spectrum panel.
     */
    public void refreshSpectrumPanel() {

        int row = spectraTbl.getSelectedRow();

        if (row != -1 && !titleToSetMap.isEmpty() ) {
            // The spectrum id.
            try {
                selectedSpectrum = titleToSetMap.get(spectraTbl.getValueAt(row, spectraTbl.convertColumnIndexToView(1))).getMascotGenericFile();

                ArrayList<Charge> precursorCharges = new ArrayList<Charge>();
                precursorCharges.add(new Charge(selectedSpectrum.getCharge(), Charge.PLUS));
                HashMap<Double,Peak> peakMap = new HashMap<Double, Peak>();
                HashMap<Double,Double> mgfPeaks = selectedSpectrum.getPeaks();
                Iterator<Double> iterator = mgfPeaks.keySet().iterator();
                while (iterator.hasNext()) {
                    Double mass = iterator.next();
                    peakMap.put(mass, new Peak(mass, mgfPeaks.get(mass)));
                }
                MSnSpectrum currentSpectrum = new MSnSpectrum(2, new Precursor(0.0, selectedSpectrum.getPrecursorMZ(), precursorCharges), "no title", peakMap, "no filename");

                spectrumPanel = new SpectrumPanel(
                        currentSpectrum.getMzValuesAsArray(), currentSpectrum.getIntensityValuesAsArray(),
                        selectedSpectrum.getPrecursorMZ(), selectedSpectrum.getCharge() + "+",
                        "", 40, false, false, false, 2, false);

                updateAnnotationMenus(selectedSpectrum.getCharge());

                // Update the annotations
                updateAnnotations();

                spectrumJPanel.removeAll();
                spectrumJPanel.add(spectrumPanel);
                spectrumJPanel.revalidate();
                spectrumJPanel.repaint();
            } catch (SQLException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            } catch (IOException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }
    }

    /**
     * Updates the annotations.
     */
    private void updateAnnotations() {
        int row = denovoTbl.getSelectedRow();
        if (row != -1) {
            Pepnovohit hit = titleToSetMap.get(selectedSpectrum.getTitle()).getDenovoHits().get(row);
            if (hit != null) {
                addAnnotations(hit);
            }
        }
    }

    /**
     * Update the denovo hit table based on the spectrum selected via mouse click.
     */
    private void refreshDenovoTable() {
        // Set the cursor into the wait status.
        this.setCursor(new Cursor(Cursor.WAIT_CURSOR));

        ((DefaultTableModel) denovoTbl.getModel()).setRowCount(0);

        int row = spectraTbl.getSelectedRow();

        // Condition if one row is selected.
        if (row != -1 && !titleToSetMap.isEmpty()) {

            String spectrumName = spectraTbl.getValueAt(row, 1).toString().trim();
            if (titleToSetMap.containsKey(spectrumName)) {
                List<Pepnovohit> pepnovoList = titleToSetMap.get(spectrumName).getDenovoHits();

                for (int i = 0; i < pepnovoList.size(); i++) {
                    Pepnovohit hit = pepnovoList.get(i);
                    if (hit != null) {

                        ((DefaultTableModel) denovoTbl.getModel()).addRow(new Object[]{
                                i + 1,
                                hit.getSequence(),
                                hit.getRankscore().doubleValue(),
                                hit.getPnvscore().doubleValue(),
                                hit.getN_gap().doubleValue(),
                                hit.getC_gap().doubleValue(),
                                hit.getPrecursor_mh().doubleValue(),
                                hit.getCharge()
                        });
                    }
                }
            }
            denovoTbl.getSelectionModel().setSelectionInterval(0, 0);
        }
        // Set the cursor back into the default status.
        this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
    }

    /**
     * Adds spectrum annotations based on the selected de novo hit.
     *
     * @param hit
     */
    private void addAnnotations(Pepnovohit hit) {

        int row = spectraTbl.getSelectedRow();

        if (row != -1) {
            // convert the spectrum
            ArrayList<Charge> precursorCharges = new ArrayList<Charge>();
            precursorCharges.add(new Charge(selectedSpectrum.getCharge(), Charge.PLUS));
            HashMap<Double,Peak> peakMap = new HashMap<Double, Peak>();
            HashMap<Double,Double> mgfPeaks = selectedSpectrum.getPeaks();
            Iterator<Double> iterator = mgfPeaks.keySet().iterator();
            while (iterator.hasNext()) {
                Double mass = iterator.next();
                peakMap.put(mass, new Peak(mass, mgfPeaks.get(mass)));
            }
            MSnSpectrum currentSpectrum = new MSnSpectrum(2, new Precursor(0.0, selectedSpectrum.getPrecursorMZ(), precursorCharges), "no title", peakMap, "no filename");

            // add the annotations
            SpectrumAnnotator spectrumAnnotator = new SpectrumAnnotator();

            // show annotated peaks in foreground, non-annotated in background
            spectrumPanel.showAnnotatedPeaksOnly(!annotationPreferences.showAllPeaks());
            if(hit.getSequence().contains("+")) {
                int index = hit.getSequence().indexOf("+");
                hit.setSequence(hit.getSequence().substring(0, index) + hit.getSequence().substring(index + 3, hit.getSequence().length()));
            }
            peptide = new Peptide(hit.getSequence(), new ArrayList<String>(), new ArrayList<ModificationMatch>());

            // Get the de novo search parameters
            int charge = (int) hit.getCharge();
            annotationPreferences.setCurrentSettings(peptide, charge, true);

            ArrayList<IonMatch> annotations = spectrumAnnotator.getSpectrumAnnotation(
                    annotationPreferences.getIonTypes(),
                    annotationPreferences.getNeutralLosses(),
                    annotationPreferences.getValidatedCharges(),
                    charge,
                    currentSpectrum, peptide,
                    currentSpectrum.getIntensityLimit(0.0),
                    0.5,
                    false);

            spectrumPanel.setAnnotations(SpectrumAnnotator.getSpectrumAnnotation(annotations));

            // add de novo sequencing
            spectrumPanel.addAutomaticDeNovoSequencing(peptide, annotations,
                    PeptideFragmentIon.B_ION,
                    PeptideFragmentIon.Y_ION, 
                    annotationPreferences.getDeNovoCharge(),
                    annotationPreferences.showForwardIonDeNovoTags(),
                    annotationPreferences.showRewindIonDeNovoTags());

            updateAnnotationMenus(charge);

        }
    }

    /**
     * This method updates the results in the panel.
     *
     * @param denovoSearchResultSet
     */
    public void updateResults(DenovoSearchResult denovoSearchResultSet) {
        titleToSetMap = denovoSearchResultSet.getTitleToHitSet();

        // Update the spectra table.
        refreshSpectraTable();

        enableAnnotationMenuBar();
    }

    /**
     * This method updates the spectra table.
     */
    private void refreshSpectraTable() {
        ((DefaultTableModel) spectraTbl.getModel()).setRowCount(0);

        if (titleToSetMap != null) {
            int i = 1;
            Set<String> spectrumTitles = titleToSetMap.keySet();
            for(String title : spectrumTitles) {
                ((DefaultTableModel) spectraTbl.getModel()).addRow(new Object[]{
                        i++,
                        title
                });
            }
            spectraTbl.getSelectionModel().setSelectionInterval(0, 0);
        }
    }


    private void updateModificationProfile(PeptideMatch peptideMatch, boolean selectedPeptideProfile) {
        try {
            ArrayList<ModificationProfile> profiles = getModificationProfile(peptideMatch.getTheoreticPeptide());

            SequenceModificationPanel sequenceModificationPanel =
                    new SequenceModificationPanel(peptideMatch.getTheoreticPeptide().getNTerminal() + "-"
                            + peptideMatch.getTheoreticPeptide().getSequence()
                            + "-" + peptideMatch.getTheoreticPeptide().getCTerminal(),
                            profiles, true);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Returns the content of a Modification Profile cell for a desired peptide.
     *
     * @param peptide   The sequence of the peptide
     * @return          The modification profile
     */
    private ArrayList<ModificationProfile> getModificationProfile(Peptide peptide) {
        ArrayList<ModificationProfile> profiles = new ArrayList<ModificationProfile>();
        //Color ptmColor = peptideShakerGUI.getSearchParameters().getModificationProfile().getColor(ptmName);
        //ModificationProfile tempProfile = new ModificationProfile(ptmName, new double[peptide.getSequence().length()][2], ptmColor);
        return profiles;
    }

    /**
     * Update the annotation menu bar with the current annotation preferences.
     *
     * @param precursorCharge The charge of the precursor.
     */
    public void updateAnnotationMenus(int precursorCharge) {

        ArrayList<String> selectedLosses = new ArrayList<String>();

        for (JCheckBoxMenuItem lossMenuItem : lossMenus.values()) {

            if (lossMenuItem.isSelected()) {
                selectedLosses.add(lossMenuItem.getText());
            }

            lossMenu.remove(lossMenuItem);
        }

        lossMenu.setVisible(true);
        //lossSplitter.setVisible(true);
        lossMenus.clear();

        HashMap<String, NeutralLoss> neutralLosses = new HashMap<String, NeutralLoss>();

        for (NeutralLoss neutralLoss : IonFactory.getInstance().getDefaultNeutralLosses()) {
            neutralLosses.put(neutralLoss.name, neutralLoss);
        }


        ArrayList<String> names = new ArrayList<String>(neutralLosses.keySet());
        Collections.sort(names);

        ArrayList<String> finalSelectedLosses = selectedLosses;
        boolean selected;

        if (names.isEmpty()) {
            lossMenu.setEnabled(false);
            //lossSplitter.setVisible(false);
        } else {
            for (int i = 0; i < names.size(); i++) {

                if (annotationPreferences.areNeutralLossesSequenceDependant()) {
                    selected = false;
                    for (NeutralLoss neutralLoss : annotationPreferences.getNeutralLosses().getAccountedNeutralLosses()) {
                        if (neutralLoss.isSameAs(neutralLoss)) {
                            selected = true;
                            break;
                        }
                    }
                } else {
                    if (finalSelectedLosses.contains(names.get(i))) {
                        selected = true;
                    } else {
                        selected = false;
                    }
                }

                JCheckBoxMenuItem lossMenuItem = new JCheckBoxMenuItem(names.get(i));
                lossMenuItem.setSelected(selected);
                lossMenuItem.addActionListener(new java.awt.event.ActionListener() {

                    public void actionPerformed(java.awt.event.ActionEvent evt) {
                        annotationPreferences.useAutomaticAnnotation(false);
                        annotationPreferences.setNeutralLossesSequenceDependant(false);
                        updateAnnotationPreferences();
                    }
                });
                lossMenus.put(neutralLosses.get(names.get(i)), lossMenuItem);
                lossMenu.add(lossMenuItem, i);
            }
        }

        ArrayList<String> selectedCharges = new ArrayList<String>();

        for (JCheckBoxMenuItem chargeMenuItem : chargeMenus.values()) {

            if (chargeMenuItem.isSelected()) {
                selectedCharges.add(chargeMenuItem.getText());
            }

            chargeMenu.remove(chargeMenuItem);
        }

        chargeMenus.clear();

        if (precursorCharge == 1) {
            precursorCharge = 2;
        }

        final ArrayList<String> finalSelectedCharges = selectedCharges;

        for (int charge = 1; charge < precursorCharge; charge++) {

            JCheckBoxMenuItem chargeMenuItem = new JCheckBoxMenuItem(charge + "+");

            if (annotationPreferences.useAutomaticAnnotation()) {
                chargeMenuItem.setSelected(annotationPreferences.getValidatedCharges().contains(charge));
            } else {
                if (finalSelectedCharges.contains(charge + "+")) {
                    chargeMenuItem.setSelected(true);
                } else {
                    chargeMenuItem.setSelected(false);
                }
            }

            chargeMenuItem.addActionListener(new java.awt.event.ActionListener() {

                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    annotationPreferences.useAutomaticAnnotation(false);
                    updateAnnotationPreferences();
                }
            });

            chargeMenus.put(charge, chargeMenuItem);
            chargeMenu.add(chargeMenuItem);
        }
    }

    /**
     * Save the current annotation preferences selected in the annotation menus.
     */
    public void updateAnnotationPreferences() {

        annotationPreferences.clearIonTypes();
        if (aIonCheckBoxMenuItem.isSelected()) {
            annotationPreferences.addIonType(Ion.IonType.PEPTIDE_FRAGMENT_ION, PeptideFragmentIon.A_ION);
        }
        if (bIonCheckBoxMenuItem.isSelected()) {
            annotationPreferences.addIonType(Ion.IonType.PEPTIDE_FRAGMENT_ION, PeptideFragmentIon.B_ION);
        }
        if (cIonCheckBoxMenuItem.isSelected()) {
            annotationPreferences.addIonType(Ion.IonType.PEPTIDE_FRAGMENT_ION, PeptideFragmentIon.C_ION);
        }
        if (xIonCheckBoxMenuItem.isSelected()) {
            annotationPreferences.addIonType(Ion.IonType.PEPTIDE_FRAGMENT_ION, PeptideFragmentIon.X_ION);
        }
        if (yIonCheckBoxMenuItem.isSelected()) {
            annotationPreferences.addIonType(Ion.IonType.PEPTIDE_FRAGMENT_ION, PeptideFragmentIon.Y_ION);
        }
        if (zIonCheckBoxMenuItem.isSelected()) {
            annotationPreferences.addIonType(Ion.IonType.PEPTIDE_FRAGMENT_ION, PeptideFragmentIon.Z_ION);
        }
        if (precursorCheckMenuItem.isSelected()) {
            annotationPreferences.addIonType(Ion.IonType.PRECURSOR_ION);
        }
        if (immoniumIonsCheckMenuItem.isSelected()) {
            annotationPreferences.addIonType(Ion.IonType.IMMONIUM_ION);
        }

        annotationPreferences.clearNeutralLosses();

        for (NeutralLoss neutralLoss : lossMenus.keySet()) {
            if (lossMenus.get(neutralLoss).isSelected()) {
                annotationPreferences.addNeutralLoss(neutralLoss);
            }
        }

        annotationPreferences.clearCharges();

        for (int charge : chargeMenus.keySet()) {
            if (chargeMenus.get(charge).isSelected()) {
                annotationPreferences.addSelectedCharge(charge);
            }
        }

        annotationPreferences.setShowAllPeaks(allCheckBoxMenuItem.isSelected());
        //annotationPreferences.setShowBars(barsCheckBoxMenuItem.isSelected());

        annotationPreferences.setShowForwardIonDeNovoTags(forwardIonsDeNovoCheckBoxMenuItem.isSelected());
        annotationPreferences.setShowRewindIonDeNovoTags(rewindIonsDeNovoCheckBoxMenuItem.isSelected());

        if (deNovoChargeOneJRadioButtonMenuItem.isSelected()) {
            annotationPreferences.setDeNovoCharge(1);
        } else {
            annotationPreferences.setDeNovoCharge(2);
        }

        // Refresh the spectrum panel
        refreshSpectrumPanel();
    }
}

